#include "si_toolchain.h"
#include "C8051F330_defs.h"
#include "adc.h"
#include "timer.h"
#include "sio.h"
#include "key.h"
#include "console.h"
#include <stdlib.h>
#include "lib.h"

sbit POWER_LED = P0^6;
sbit FLASH_SW = P1^4;
sbit LED_SW = P1^3;
sbit POWER_CTL = P0^1;
sbit CHARGE_CTL = P1^5;
sbit CHARGE_STATUS = P1^6;



void Port_Init()
{
    // P0.0  -  Unassigned,  Open-Drain, Digital
    // P0.1  -  Unassigned,  Push-Pull,  Digital
    // P0.2  -  Unassigned,  Open-Drain, Digital
    // P0.3  -  Unassigned,  Open-Drain, Digital
    // P0.4  -  TX0 (UART0), Open-Drain, Digital
    // P0.5  -  RX0 (UART0), Open-Drain, Digital
    // P0.6  -  Unassigned,  Push-Pull,  Digital
    // P0.7  -  Unassigned,  Open-Drain, Digital

    // P1.0  -  Unassigned,  Open-Drain, Analog
    // P1.1  -  Unassigned,  Open-Drain, Digital
    // P1.2  -  Unassigned,  Open-Drain, Digital
    // P1.3  -  Unassigned,  Push-Pull,  Digital
    // P1.4  -  Unassigned,  Push-Pull,  Digital
    // P1.5  -  Unassigned,  Open-Drain, Digital
    // P1.6  -  Unassigned,  Open-Drain, Analog
    // P1.7  -  Unassigned,  Open-Drain, Digital

		P1MDIN    = 0x3E;
    P1SKIP    = 0x01;
    P0MDOUT   = 0x46;
	  P1MDOUT   = 0x3A;
    XBR0      = 0x01;
    XBR1      = 0x40;
}

unsigned int Next_Compare_Value;       // Next edge to be sent out in HSO mode

#define CHARGE_FREQUENCY 100000         // Frequency to blink LED at in Hz
#define T0_CLOCKS 123                  // Use 245 clocks per T0 Overflow

// SYSCLK cycles per interrupt
#define PCA_TIMEOUT ((SYSCLK/T0_CLOCKS)/CHARGE_FREQUENCY)

#define CHARGE_MAX_COUNT 10
static int _chargeRemindCount = CHARGE_MAX_COUNT;

static int _chargeState = 0;

static void FlashCharge(int sw)
{
	if( _chargeState != sw){
		CR = sw;                             // Start PCA
		TR0 = sw;                            // Start Timer 0
		_chargeState = sw;
	}
	
	// charge over hold 1 
	if( sw == 0 ){
		CHARGE_CTL = 1;
	}
}

static unsigned char get_battery_vol()
{
	int i;
	int sum = 0;
	double vol;
	
	Adc_SetPort(0x08);
	
	for(i = 0; i < 10; i++){
		int val = Adc_Read();
			sum += val;
	}
	
	vol = (double)sum / 10;
	
	return (unsigned char)(vol * 2.2043);
}

static unsigned char get_charge_vol()
{
	int i;
	int sum = 0;
	double vol;
	
	Adc_SetPort(0x0E);
	
	for(i = 0; i < 10; i++){
		int val = Adc_Read();
			sum += val;
	}
	
	vol = (double)sum / 10;
	
	return (unsigned char)(vol);
}

static void FlashChargeProcess(void)
{
	unsigned char vol;
	if( FLASH_SW == 0){
		_chargeRemindCount = CHARGE_MAX_COUNT;
	}
	
	FlashCharge(_chargeRemindCount > 0);
	_chargeRemindCount = _chargeRemindCount < 0 ? 0 : _chargeRemindCount;
}

//-----------------------------------------------------------------------------
// PCA0_Init
//-----------------------------------------------------------------------------
//
// Return Value : None
// Parameters   : None
//
// This function configures the PCA time base, and sets up frequency output
// mode for Module 0 (CEX0 pin).
//
// The frequency generated at the CEX0 pin is equal to CEX0_FREQUENCY Hz,
// which is defined in the "Global Constants" section at the beginning of the
// file.
//
// The PCA time base in this example is configured to use SYSCLK / 12.
// The frequency range that can be generated using this example is ~4 kHz to
// ~1 MHz when the processor clock is 24.5 MHz.  Using different PCA clock
// sources or a different processor clock will generate different frequency
// ranges.
//
//    -------------------------------------------------------------------------
//    How "Frequency Output Mode" Works:
//
//       The PCA's Frequency Output Mode works by toggling an output pin every
//    "N" PCA clock cycles.  The value of "N" should be loaded into the PCA0CPH
//    register for the module being used (in this case, module 0).  Whenever
//    the register PCA0L (PCA counter low byte) and the module's PCA0CPL value
//    are equivalent, two things happen:
//
//    1) The port pin associated with the PCA module toggles logic state
//    2) The value stored in PCA0CPH is added to PCA0CPL.
//
//    Using this mode, a square wave is produced at the output port pin of the
//    PCA module. The speed of the waveform can be changed by changing the
//    value of the PCA0CPH register.
//    -------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
void PCA0_Init (void)
{
   // Configure Timer 0 for 8-bit auto-reload mode, using SYSCLK as time base
   TMOD &= 0xF0;                       // Clear all T0 control bits
   TMOD |= 0x02;                       // 8-bit auto-reload timer
   CKCON |= 0x04;                      // T0 uses SYSCLK
   TH0 = -T0_CLOCKS;                   // Set up reload value
   TL0 = -T0_CLOCKS;                   // Set up initial value

   // Configure PCA time base; overflow interrupt disabled
   PCA0CN = 0x00;                      // Stop counter; clear all flags
   PCA0MD = 0x04;                      // Use Timer 0 as time base

   PCA0CPM0 = 0x49;                    // Module 0 = Software Timer Mode,
                                       // Enable Module 0 Interrupt flag,
                                       // Enable ECOM bit

   PCA0L = 0x00;                       // Reset PCA Counter Value to 0x0000
   PCA0H = 0x00;

   PCA0CPL0 = PCA_TIMEOUT & 0x00FF;    // Set up first match
   PCA0CPH0 = (PCA_TIMEOUT & 0xFF00) >> 8;

   // Set up the variable for the following match
   Next_Compare_Value = PCA0CP0 + PCA_TIMEOUT;

   EIE1 |= 0x10;                       // Enable PCA interrupts
}



void Oscillator_Init()
{
   OSCICN |= 0x03;                     // Configure internal oscillator for its maximum frequency

   RSTSRC = 0x04;                         // enable missing clock detector
}

void Interrupts_Init()
{
   EA = 1;
}

static unsigned char _heart_packet[] = { 0xFB, 0x00, 0x00, 0x00, 0xFF };



static unsigned char *make_heart_packet(void)
{
	 unsigned char vol = get_battery_vol();
	 _heart_packet[1] = vol;
	 _heart_packet[2] = get_charge_vol();
	 _heart_packet[3] = LED_SW;
	
	return _heart_packet;
}


static void FlashMe(void)
{
	FLASH_SW = 0;
	delay_1ms();
	FLASH_SW = 1;
	_chargeRemindCount = CHARGE_MAX_COUNT;
}

static enConsoleResult Flash(int argc, char** argv)
{
	if( _chargeRemindCount == 0){
		FlashMe();
		return CE_OK;
	}
	
	return CE_ACCESS_FORBIDDEN;
}

static const COMMAND _FlashCommand = {  
	DEFAULT_NODE,
	"FLS",
	Flash,
};


static enConsoleResult Status(int argc, char** argv)
{
	com_write(make_heart_packet(), sizeof(_heart_packet));
	return CE_OK;
}

static const COMMAND _StatusCommand = {  
	DEFAULT_NODE,
	"STA",
	Status,
};

static enConsoleResult Led(int argc, char** argv)
{
	if( argc == 2){
		int sw = atoi(argv[1]);
		
		LED_SW = sw == 0 ? 1 : 0;
		
		return CE_OK;
	}
	
	return CE_ACCESS_FORBIDDEN;
}

static const COMMAND _LedCommand = {  
	DEFAULT_NODE,
	"LED",
	Led,
};

// Initialization function for device,
// Call Init_Device() from your main program
void Init_Device(void)
{
	Timer2_Init(SYSCLK / 12 / 100);    // Init Timer2 to generate interrupts at a 100Hz rate
	com_initialize();
	Adc_Init();
	Port_Init();
	Oscillator_Init();
	PCA0_Init();
	FlashCharge(0);
	Powerkey_init();
	Interrupts_Init();
	ConsoleInit();
	ConsoleRegCmd(&_FlashCommand);
	ConsoleRegCmd(&_LedCommand);
	ConsoleRegCmd(&_StatusCommand);
}


static int _1s_tick = 0;
static int _20s_tick = 0;

static void PowerOff(void)
{
	int i;
	for(i=0; i < 6; i++){
		POWER_LED = !POWER_LED;
		delay_ms(200);
	}
}

static unsigned int vol = 0;

static void Key_Process(void)
{
    enKeyState key_state = Powerkey_Scan();
    //按键处理
    if( key_state == KEY_DOWN) {

    }else if( key_state == KEY_LONG) {
				PowerOff();
				FLASH_SW = 1;
        POWER_CTL = 0;
				delay_ms(2000);
    }
}

//-----------------------------------------------------------------------------
// PCA0_ISR
//-----------------------------------------------------------------------------
//
// Return Value : None
// Parameters   : None
//
// This is the ISR for the PCA.  It handles the case when a match occurs on
// channel 0, and updates the PCA0CPn compare register with the value held in
// the global variable "Next_Compare_Value".
//
//-----------------------------------------------------------------------------
void PCA0_ISR (void) interrupt 11
{
   if (CCF0)                           // If Module 0 caused the interrupt
   {
      CCF0 = 0;                        // Clear module 0 interrupt flag.

      PCA0CPL0 = (Next_Compare_Value & 0x00FF);
      PCA0CPH0 = (Next_Compare_Value & 0xFF00)>>8;
		 
			CHARGE_CTL = ~CHARGE_CTL;                      // Invert the LED pin

      // Set up the variable for the following edge
      Next_Compare_Value = PCA0CP0 + PCA_TIMEOUT;
   }
   else                                // Interrupt was caused by other bits.
   {
      PCA0CN &= ~0x86;                 // Clear other interrupt flags for PCA
   }
}

void charge_dec_proc(void)
{
	unsigned char vol;								
	vol = get_charge_vol();
	if( vol >= 16){ //充电状态超过1.8V停止PWM输出
		_chargeRemindCount = 0;
	}else{
		if( _chargeRemindCount > 0 ){
			_chargeRemindCount--;
		}
	}
}


int main()
{
	// disable watchdog timer
    PCA0MD &= ~0x40;                       // WDTE = 0 (clear watchdog timer enable)
    POWER_LED = 1;
		POWER_CTL = 1;
		FLASH_SW = 1;

    Init_Device();

    while(1){
        if( Timer2_IsTimeout()){ //10ms timeout
            Key_Process();
						FlashChargeProcess();
						ConsoleRun();
            //1秒过程
            _1s_tick++;
            if( _1s_tick == 100 ){
                _1s_tick = 0;
                _20s_tick++;
								charge_dec_proc();

            }

            //20 秒的心跳包
            if( _20s_tick == 20 ){
                _20s_tick = 0;
                com_write(make_heart_packet(), sizeof(_heart_packet));
            }
        }
    }

    return 0;
}


